#ifndef MOVING_ENTITY_H_
#define MOVING_ENTITY_H_


//------------------------------------------------------------------------
//
//  Name:   MovingEntity.h
//
//  Desc:   A base class defining an entity that moves. The entity has 
//          a local coordinate system and members for defining its
//          mass and velocity.
//
//  Author: Mat Buckland (fup@ai-junkie.com)
//
//------------------------------------------------------------------------



#include "Entities\BaseEntity.h"
#include "Maths\Vector2.h"
#include "Maths\Math.h"
#include "Maths\Matrix3.h"

namespace CasaEngine
{

class MovingEntity : public BaseEntity
{
protected:
  
  Vector2F    m_vVelocity;
  
  //a normalized vector pointing in the direction the entity is heading. 
  Vector2F    m_vHeading;

  //a vector perpendicular to the heading vector
  Vector2F    m_vSide; 

  float      m_fMass;
  
  //the maximum speed this entity may travel at.
  float      m_fMaxSpeed;

  //the maximum force this entity can produce to power itself 
  //(think rockets and thrust)
  float      m_fMaxForce;
  
  //the maximum rate (radians per second)this MovingEntity can rotate         
  float      m_fMaxTurnRate;

public:


  MovingEntity(Vector2F position,
               float   radius,
               Vector2F velocity,
               float   max_speed,
               Vector2F heading,
               float   mass,
               Vector2F scale,
               float   turn_rate,
               float   max_force):
                                  m_vHeading(heading),
                                  m_vVelocity(velocity),
                                  m_fMass(mass),
                                  m_vSide(m_vHeading.Perp()),
                                  m_fMaxSpeed(max_speed),
                                  m_fMaxTurnRate(turn_rate),
                                  m_fMaxForce(max_force)
  {
    //m_vPosition = position;
    //m_fBoundingRadius = radius; 
    //m_vScale = scale;
  }


  virtual ~MovingEntity(){}

  //accessors
  Vector2F  Velocity()const{return m_vVelocity;}
  void      SetVelocity(const Vector2F& NewVel){m_vVelocity = NewVel;}
  
  float    Mass()const{return m_fMass;}
  
  Vector2F  Side()const{return m_vSide;}

  float    MaxSpeed()const{return m_fMaxSpeed;}                       
  void      SetMaxSpeed(float new_speed){m_fMaxSpeed = new_speed;}
  
  float    MaxForce()const{return m_fMaxForce;}
  void      SetMaxForce(float mf){m_fMaxForce = mf;}

  bool      IsSpeedMaxedOut()const{return m_fMaxSpeed*m_fMaxSpeed >= m_vVelocity.LengthSq();}
  float    Speed()const{return m_vVelocity.Length();}
  float    SpeedSq()const{return m_vVelocity.LengthSq();}
  
  Vector2F  Heading()const{return m_vHeading;}
  void      SetHeading(Vector2F new_heading);
  bool      RotateHeadingToFacePosition(Vector2F target);

  float    MaxTurnRate()const{return m_fMaxTurnRate;}
  void      SetMaxTurnRate(float val){m_fMaxTurnRate = val;}

};


//--------------------------- RotateHeadingToFacePosition ---------------------
//
//  given a target position, this method rotates the entity's heading and
//  side vectors by an amount not greater than m_fMaxTurnRate until it
//  directly faces the target.
//
//  returns true when the heading is facing in the desired direction
//-----------------------------------------------------------------------------
inline bool MovingEntity::RotateHeadingToFacePosition(Vector2F target)
{
  Vector2F toTarget = target - m_vPosition;
  toTarget.Normalize();

  float dot = m_vHeading.Dot(toTarget);

  //some compilers lose accuracy so the value is clamped to ensure it
  //remains valid for the acos
  Clamp(dot, -1, 1);

  //first determine the angle between the heading vector and the target
  float angle = acos(dot);

  //return true if the player is facing the target
  if (angle < 0.00001f) return true;

  //clamp the amount to turn to the max turn rate
  if (angle > m_fMaxTurnRate) angle = m_fMaxTurnRate;
  
  //The next few lines use a rotation matrix to rotate the player's heading
  //vector accordingly
	Matrix3 RotationMatrix;
  
  //notice how the direction of rotation has to be determined when creating
  //the rotation matrix
	RotationMatrix.Rotate(angle * m_vHeading.Sign(toTarget));	
  RotationMatrix.TransformVector2F(m_vHeading);
  RotationMatrix.TransformVector2F(m_vVelocity);

  //finally recreate m_vSide
  m_vSide = m_vHeading.Perp();

  return false;
}


//------------------------- SetHeading ----------------------------------------
//
//  first checks that the given heading is not a vector of zero length. If the
//  new heading is valid this fumction sets the entity's heading and side 
//  vectors accordingly
//-----------------------------------------------------------------------------
inline void MovingEntity::SetHeading(Vector2F new_heading)
{
  CASAENGINE_ASSERT( (new_heading.LengthSq() - 1.0f) < 0.00001f);
  
  m_vHeading = new_heading;

  //the side vector must always be perpendicular to the heading
  m_vSide = m_vHeading.Perp();
}

} // namespace CasaEngine

#endif // MOVING_ENTITY_H_
